한국어

스키마 스티칭으로 GraphQL 페더레이션의 강력한 기능을 활용하세요. 여러 서비스로부터 통합된 GraphQL API를 구축하여 확장성과 유지보수성을 향상시키는 방법을 배워보세요.

GraphQL 페더레이션: 스키마 스티칭 - 종합 가이드

끊임없이 진화하는 현대 애플리케이션 개발 환경에서 확장 가능하고 유지보수하기 쉬운 아키텍처의 필요성이 무엇보다 중요해졌습니다. 마이크로서비스는 내재된 모듈성과 독립적인 배포 가능성 덕분에 인기 있는 해결책으로 부상했습니다. 그러나 수많은 마이크로서비스를 관리하는 것은 특히 클라이언트 애플리케이션에 통합된 API를 노출할 때 복잡성을 야기할 수 있습니다. 바로 이 지점에서 GraphQL 페더레이션, 특히 스키마 스티칭이 중요한 역할을 합니다.

GraphQL 페더레이션이란?

GraphQL 페더레이션은 여러 개의 기본 GraphQL 서비스(주로 마이크로서비스를 나타냄)로부터 단일의 통합된 GraphQL API를 구축할 수 있게 해주는 강력한 아키텍처입니다. 이를 통해 개발자들은 여러 서비스에 걸친 데이터를 마치 하나의 그래프인 것처럼 쿼리할 수 있어, 클라이언트 경험을 단순화하고 클라이언트 측의 복잡한 오케스트레이션 로직의 필요성을 줄여줍니다.

GraphQL 페더레이션에는 두 가지 주요 접근 방식이 있습니다:

이 글에서는 스키마 스티칭에 초점을 맞추어 그 개념, 장점, 한계 및 실제 구현 방법을 탐구합니다.

스키마 스티칭 이해하기

스키마 스티칭은 여러 GraphQL 스키마를 하나의 일관된 스키마로 병합하는 과정입니다. 이 통합된 스키마는 클라이언트로부터 기본 서비스의 복잡성을 숨기는 파사드(facade) 역할을 합니다. 클라이언트가 스티칭된 스키마에 요청을 보내면, 게이트웨이는 지능적으로 요청을 적절한 기본 서비스로 라우팅하고, 데이터를 검색한 후, 결과를 결합하여 클라이언트에게 반환합니다.

이렇게 생각해 보세요. 각기 다른 요리를 전문으로 하는 여러 레스토랑(서비스)이 있습니다. 스키마 스티칭은 각 레스토랑의 모든 요리를 결합한 통합 메뉴와 같습니다. 고객(클라이언트)이 이 통합 메뉴에서 주문하면, 주문은 지능적으로 해당 레스토랑의 주방으로 전달되고, 음식이 준비된 후 하나의 배달로 합쳐져 고객에게 전달됩니다.

스키마 스티칭의 핵심 개념

스키마 스티칭의 장점

스키마 스티칭은 마이크로서비스 아키텍처를 채택하는 조직에 여러 가지 강력한 이점을 제공합니다:

스키마 스티칭의 한계

스키마 스티칭은 수많은 장점을 제공하지만, 그 한계를 인지하는 것이 중요합니다:

스키마 스티칭의 실제 구현

Node.js와 `graphql-tools` 라이브러리(스키마 스티칭에 널리 사용되는 선택지)를 사용하여 스키마 스티칭을 구현하는 간단한 예제를 살펴보겠습니다. 이 예제는 사용자 서비스제품 서비스라는 두 개의 마이크로서비스를 포함합니다.

1. 원격 스키마 정의하기

먼저, 각 원격 서비스에 대한 GraphQL 스키마를 정의합니다.

사용자 서비스 (user-service.js):


const { buildSchema } = require('graphql');

const userSchema = buildSchema(`
  type User {
    id: ID!
    name: String
    email: String
  }

  type Query {
    user(id: ID!): User
  }
`);

const users = [
  { id: '1', name: 'Alice Smith', email: 'alice@example.com' },
  { id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];

const userRoot = {
  user: (args) => users.find(user => user.id === args.id),
};

module.exports = {
  schema: userSchema,
  rootValue: userRoot,
};

제품 서비스 (product-service.js):


const { buildSchema } = require('graphql');

const productSchema = buildSchema(`
  type Product {
    id: ID!
    name: String
    price: Float
    userId: ID!  # 사용자 서비스에 대한 외래 키
  }

  type Query {
    product(id: ID!): Product
  }
`);

const products = [
  { id: '101', name: 'Laptop', price: 1200, userId: '1' },
  { id: '102', name: 'Smartphone', price: 800, userId: '2' },
];

const productRoot = {
  product: (args) => products.find(product => product.id === args.id),
};

module.exports = {
  schema: productSchema,
  rootValue: productRoot,
};

2. 게이트웨이 서비스 생성하기

이제 두 스키마를 함께 스티칭할 게이트웨이 서비스를 생성합니다.

게이트웨이 서비스 (gateway.js):


const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');

async function createRemoteSchema(uri) {
  const fetcher = async (params) => {
    const response = await fetch(uri, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(params),
    });
    return response.json();
  };

  const schema = await introspectSchema(fetcher);
  return makeRemoteExecutableSchema({
    schema,
    fetcher,
  });
}

async function main() {
  const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
  const productSchema = await createRemoteSchema('http://localhost:4002/graphql');

  const stitchedSchema = stitchSchemas({
    subschemas: [
      { schema: userSchema },
      { schema: productSchema },
    ],
    typeDefs: `
      extend type Product {
        user: User
      }
    `,
    resolvers: {
      Product: {
        user: {
          selectionSet: `{ userId }`,
          resolve(product, args, context, info) {
            return info.mergeInfo.delegateToSchema({
              schema: userSchema,
              operation: 'query',
              fieldName: 'user',
              args: {
                id: product.userId,
              },
              context,
              info,
            });
          },
        },
      },
    },
  });

  const app = express();
  app.use('/graphql', graphqlHTTP({
    schema: stitchedSchema,
    graphiql: true,
  }));

  app.listen(4000, () => console.log('게이트웨이 서버가 http://localhost:4000/graphql 에서 실행 중입니다'));
}

main().catch(console.error);

3. 서비스 실행하기

사용자 서비스와 제품 서비스를 서로 다른 포트에서 실행해야 합니다. 예를 들면 다음과 같습니다:

사용자 서비스 (포트 4001):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4001, () => console.log('사용자 서비스가 http://localhost:4001/graphql 에서 실행 중입니다'));

제품 서비스 (포트 4002):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4002, () => console.log('제품 서비스가 http://localhost:4002/graphql 에서 실행 중입니다'));

4. 스티칭된 스키마에 쿼리하기

이제 게이트웨이(포트 4000에서 실행 중)를 통해 스티칭된 스키마에 쿼리할 수 있습니다. 다음과 같은 쿼리를 실행할 수 있습니다:


query {
  product(id: "101") {
    id
    name
    price
    user {
      id
      name
      email
    }
  }
}

이 쿼리는 ID가 "101"인 제품을 검색하고, 사용자 서비스에서 연관된 사용자 정보도 가져옵니다. 이는 스키마 스티칭을 통해 단일 요청으로 여러 서비스에 걸쳐 데이터를 쿼리할 수 있음을 보여줍니다.

고급 스키마 스티칭 기법

기본적인 예제를 넘어, 스키마 스티칭 구현을 향상시키는 데 사용할 수 있는 몇 가지 고급 기법은 다음과 같습니다:

스키마 스티칭과 아폴로 페더레이션 중 선택하기

스키마 스티칭은 GraphQL 페더레이션을 위한 실행 가능한 옵션이지만, 아폴로 페더레이션은 고급 기능과 향상된 개발자 경험 덕분에 더 인기 있는 선택이 되었습니다. 다음은 두 접근 방식을 비교한 것입니다:

기능 스키마 스티칭 아폴로 페더레이션
스키마 정의 기존 GraphQL 스키마 언어 사용 지시어가 포함된 선언적 스키마 언어 사용
쿼리 계획 수동 쿼리 위임 필요 아폴로 게이트웨이에 의한 자동 쿼리 계획
타입 확장 제한적 지원 타입 확장을 위한 내장 지원
키 지시어 지원 안 됨 @key 지시어를 사용하여 엔티티 식별
분산 추적 수동 구현 필요 분산 추적을 위한 내장 지원
도구 및 생태계 덜 성숙한 도구 더 성숙한 도구와 대규모 커뮤니티
복잡성 대규모 시스템에서 관리하기 복잡할 수 있음 크고 복잡한 시스템을 위해 설계됨

스키마 스티칭을 선택해야 할 때:

아폴로 페더레이션을 선택해야 할 때:

실제 사례 및 사용 예시

다음은 스키마 스티칭을 포함한 GraphQL 페더레이션이 어떻게 사용될 수 있는지에 대한 실제 예시입니다:

스키마 스티칭을 위한 모범 사례

성공적인 스키마 스티칭 구현을 위해 다음 모범 사례를 따르십시오:

결론

스키마 스티칭을 이용한 GraphQL 페더레이션은 마이크로서비스 아키텍처에서 여러 서비스로부터 통합된 API를 구축하는 강력한 접근법을 제공합니다. 핵심 개념, 장점, 한계 및 구현 기법을 이해함으로써 스키마 스티칭을 활용하여 데이터 접근을 단순화하고 확장성을 향상시키며 유지보수성을 높일 수 있습니다. 아폴로 페더레이션이 더 진보된 솔루션으로 부상했지만, 스키마 스티칭은 더 간단한 시나리오나 기존 GraphQL 서비스를 통합할 때 여전히 실행 가능한 옵션입니다. 조직의 특정 요구 사항과 필요를 신중하게 고려하여 최상의 접근 방식을 선택하십시오.